
//实习开发听说课用的工具

// 防抖函数
function debounce(func, delay) {
  let timer = null;
  // 返回一个新的函数  ...代表可以传入多个变量  闭包  timer是外面引入
  return function (...args) {
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => {
      func.apply(this, args);
    }, delay);
  };
}
/* VUE组件 找到你要播放的视频组件 将以下代码写在mounted之中 */
//关闭视频播放
 this.$nextTick(()=>{
  this.$refs.videoplayer.$el.querySelector('.vjs-icon-placeholder').style.display = 'none';
 })
//视频播放的时候关闭全屏框
this.$nextTick(() => {
  console.log(this.$refs.videoplayer.$el.querySelector('.vjs-fullscreen-control.vjs-control.vjs-button'));
  // 关闭全屏
  this.$refs.videoplayer.$el.querySelector('.vjs-fullscreen-control.vjs-control.vjs-button').style.display = 'none';
});

// 节流函数
function throttle(callBack, time) {
  // callBack: 传入的回调函数
  // time: 定时器的第二个参数（多长时间触发）
  // 节流阀的状态（默认开启）
  let valve = true
  return function () {
    // 如果节流阀处于关闭状态，则不执行里面代码
    if (valve) {
      // 关闭节流阀（在里面代码没执行完之前，不能进入）
      valve = false
      // 开启定时器
      setTimeout(() => {
        // 通过 apply 改变传入的回调函数 callBack 的 this 指向
        // 通过 arguments 拿到外层函数的事件对象（箭头函数没有 this 指向）
        // 注意：事件处理函数只能有一个形参（拿到事件对象），
        // 如果要传多个参数，方法:在外面封装一个函数，在事件处理函数中调用
        callBack.apply(this, arguments)
        // 当回调函数执行完，开启节流阀（可以执行进入里面执行传入的回调函数了）
        valve = true
      }, time)
    }
  }
}


//【零】_ 判断时间  时间改变  传入字符串格式  变成number类型的秒数
// eg:1.10.36  一分十秒 =>  70[number格式]
function timeChange(time) {
  let h = 0;
  let m = 0;
  let s = 0;
  let seconds = 0;

  let length = 0;
  if (time.indexOf(':') !== -1) {
    length = time.split(':').length - 1;
    if (length === 1) {
      m = Number(time.split(':')[0]);
      s = Number(time.split(':')[1]);
      seconds = m * 60 + s;
    } else if (length === 2) {
      h = Number(time.split(':')[0]);
      m = Number(time.split(':')[1]);
      s = Number(time.split(':')[2]);
      seconds = h * 3600 + m * 60 + s;
    }
  }
  return seconds;
}

//【一】 _ 检测是否是数组
function judgeArr(arr) {
  if (Array.isArray(arr)) {
    return true
  }
}

//  【二】 _将多维数组转成一维数组
//1.纯递归调用
let newArr = [];
function flatten(arr) {
  for (let i = 0; i < arr.length; i++) {
    //如果里面还是数组 就递归重新调用一次
    if (Array.isArray(arr[i])) {
      flatten(arr[i])
    } else {
      newArr.push(arr[i])
    }
  }
}

//2.reduce + 递归调用   但是需要加上调用 flatten 函数 
/* let arr = [1, [2, [[3, 4], 5], 6]];
const flatten = arr => arr.reduce((total, current) => {
    total.concat(Array.isArray(current) ? flatten(current) : current)
}, []) */


// 【三】 _获取当前的时间  yyyy-MM-dd HH:mm:ss（没有满10就补0）
const obtainDate = () => {
  let date = new Date();
  let year = date.getFullYear();
  let month = date.getMonth() + 1;
  let day = date.getDate();
  let hours = date.getHours();
  let minu = date.getMinutes();
  let second = date.getSeconds();
  let arr = [month, day, hours, minu, second];
  arr.forEach(item => {
    //判断是否满10 未满10给补上一个0
    item < 10 ? "0" + item : item;
  })
  return year + '-' + arr[0] + '-' + arr[1] + ' ' + arr[2] + ':' + arr[3] + ':' + arr[4]
}


//【三.一】_将时间戳转化年月日
/* 
* 时间戳转化为年月日
 * @param times 时间戳
 * @param ymd 格式类型(yyyy-mm-dd,yyyy/mm/dd)
 * @param hms 可选,格式类型(hh,hh:mm,hh:mm:ss)
 * @returns {年月日}
*/
const timesToYyMmDd = (times, ymd, hms) => {
  const oDate = new Date(times)
  const oYear = oDate.getFullYear()
  const oMonth = oDate.getMonth() + 1
  const oDay = oDate.getDate()
  const oHour = oDate.getHours()
  const oMin = oDate.getMinutes()
  const oSec = oDate.getSeconds()
  let oTime // 最后拼接时间
  // 年月日格式
  switch (ymd) {
    case 'yyyy-mm-dd':
      oTime = oYear + '-' + getzf(oMonth) + '-' + getzf(oDay)
      break
    case 'yyyy/mm/dd':
      oTime = oYear + '/' + getzf(oMonth) + '/' + getzf(oDay)
      break
  }
  // 时分秒格式
  switch (hms) {
    case 'hh':
      oTime = ' ' + oTime + getzf(oHour)
      break
    case 'hh:mm':
      oTime = oTime + getzf(oHour) + ':' + getzf(oMin)
      break
    case 'hh:mm:ss':
      oTime = oTime + getzf(oHour) + ':' + getzf(oMin) + ':' + getzf(oSec)
      break
  }
  return oTime
}

//【三.二】_将年月日转化为时间戳
/*
 * 将年月日转化成时间戳
 * @param {String} time yyyy/mm/dd 或yyyy-mm-dd 或yyyy-mm-dd hh:mm 或yyyy-mm-dd hh:mm:ss
 */
export const YyMmDdToTimes = (time) => {
  return new Date(time.replace(/-/g, '/')).getTime()
}

//【四】_数组的交集 并集 差集

//1.并集
const arrAndSet = (arrone, arrtwo) => {
  return arrone.concat(arrtwo.filter(v => !arrone.includes(v)))
}

//2.交集
const arrIntersection = (arrOne, arrTwo) => {
  return arrOne.filter(v => arrTwo.includes(v))
}

//3.差集  eg: [1, 2, 3] [2, 4, 5] 差集为[1,3,4,5]
const arrDifference = (arrOne, arrTwo) => {
  return arrOne.concat(arrTwo).filter(v => !arrOne.includes(v) || !arrTwo.includes(v))
}


//【五】_数组对象求和 直接reduce就可以  不常用
const arrObjSum = (obj, key) => {
  return obj.reduce((prev, cur) => prev + cur.key, 0)
}

//【六】_数组合并
const arrConcat = (arrOne, arrTwo) => {
  return [...arrOne, ...arrTwo]  //拓展运算符 相加
}

//【七】_数组求和   
/* reduce里面可以传入两个参数 一个是函数 function 一个是我们的初始化值【通常初始化的值都是传入0】 */
const arrSum = (arr) => {
  return arr.reduce((pre, cur) => {
    return pre + cur
  }, 0)
}

//【八】_数组中是否包含某一个值  
const arrIncludeValue = (arr, value) => {
  return arr.includes(value)
}

//【九】_数组中的最大值
const arrMax = (arr) => {
  return Math.max(...arr)
}

//【十】_有关数组去重的  SET去重
const arrRemoveRepeat = arr => {
  return Array.from(new Set(arr))
}

//【十一】_数组排序  升序为true 倒序为false
const arrOrderAscend = (arr, ascendFlag = true) => {
  return arr.sort((a, b) => {
    return ascendFlag ? a - b : b - a
  })
}


/* 关于正则的一些验证方法 */

//【12】_判断是否是数字
const checkNum = (data) => /^\d{1,}$/g.test(data)

//【13】_判断是否是字母 
const checkABC = (data) => /^[a-zA-Z]+$/g.test(data)

//【14】_判断是否是手机号  只要是13,14,15,16,17,18,19开头即可
const checkTelphone = (data) => {
  const reg = /^((\+|00)86)?1[3-9]\d{9}$/g
  if (reg.test(data)) return true
}

//【15】_ 判断是否是一个正确的网址格式
const checkUrl = (url) => {
  //监听标签元素 如果是vue 可以换成 router-link
  const a = document.createElement('a')
  a.href = url
  return [
    /^(http|https):$/.test(a.protocol),
    a.host,
    a.pathname !== url,
    a.pathname !== `/${url}`
  ].find(x => !x) === undefined
}


//【16】_判断两个对象是否相等，目前只支持对象值为简单数据类型的判断 返回Boolean类型的判断
const objIsEqual = (oneObj, twoObj) => {
  /* Object.getOwnPropertyNames() 返回一个数组，该数组对元素是 obj自身拥有的枚举或不可枚举属性名称字符串。
     数组中枚举属性的顺序与通过 for...in 循环
    （或 Object.keys）迭代该对象属性时一致。数组中不可枚举属性的顺序未定义*/
  const aProps = Object.getOwnPropertyNames(oneObj);
  const bProps = Object.getOwnPropertyNames(twoObj);
  //判断两者的长度是否一样 不一样直接返回false
  if (aProps.length != bProps.length) {
    return false;
  }

  for (let i = 0; i < aProps.length; i++) {
    let propName = aProps[i];
    let propA = oneObj[propName];
    let propB = twoObj[propName];
    if (propA !== propB) {
      return false;
    }
  }
  return true;
}

/* 
 十七之前先进行一个补充 对象的浅拷贝和深拷贝的简单方法
*/


//浅拷贝用Object.assign就可以 但是里面深入的对象无法拷贝

const info = { name: "why", age: 18, friend: { name: "kobe" } };
const obj = Object.assign({}, info);

//深拷贝
const infos = { name: "why", age: 18, friend: { name: "kobe" } };
const obj = JSON.parse(JSON.stringify(infos));

//【17】_ 对象的深度克隆  一个知识点 不算是 工具类

// 现创建一个具有深度嵌套的源对象
const sourceObj = {
  nested: {
    name: 'KongLingWen',
  },
}
// 把源对象转化为JSON格式的字符串
const jsonTarget = JSON.stringify(sourceObj)
// 以解析json数据的方式转换为javascript对象
let target
try {
  target = JSON.parse(jsonTarget) //数据如果不符合JSON对象格式会抛错，这里加一个错误处理
} catch (err) {
  console.error(err)
}
target.nested.name = ''
console.log(soruceObj.nested.name) //KongLingWen

/*
 但是这种对于对象的深拷贝有一定的影响
 1.无法转变函数，属性值为函数的属性转换之后丢失
 2.JS Date对象转换成JSON对象之后 无法反解析为原对象类型 解析之后 仍然是JSON格式的字符串
 3.正则 RegExp 对象
  RegExp 对象序列化后为一个普通的 javascript 对象，同样不符合预期
 4.undefined
  序列化之后直接被过滤掉，丢失拷贝的属性
 5.NaN
  序列化之后为 null，同样不符合预期结果
 6.当需要满足以上条件的时候，可以决定手写深拷贝
*/




//【18】_ 判断字符串中是否包含某个值
const strInclude = (str, value) => {
  return str.includes(value)
}

//【19】_ 判断字符串中是否以某一个字符开头
const strBeginWith = (str, value) => {
  return str.indexOf(value) === 0
}

//【20】_ 全局替换某个字符为另一个字符
const strReplace = (str, valueOne, valueTwo) => {
  return str.replace(new RegExp(valueOne, 'g'), valueTwo)
}

//【21】_将字母全部转成大写 
const strToCapital = (str) => {
  return str.toUpperCase()
}

//【22】_ 将字母全部转成小写
const strToLowercase = (str) => {
  return str.toLowerCase()
}

//【23】_将字母全部转换成以大写开头
const strToCapitalLetter = (str) => {
  const strOne = str.toLowerCase()
  return strOne.charAt(0).toUpperCase() + strOne.slice(1)
}

    //【24】_ 十进制转换二进制
function dec2bin(decNumer) {
  // 定义变量
  var stack = new Stack()
  var remainder;
  // 循环除法
  while (decNumer > 0) {
      remainder = decNumer % 2
      decNumer = Math.floor(decNumer / 2)
      stack.push(remainder)
  }
  // 将数据取出
  var binayriStrng = ""
  while (!stack.isEmpty()) {
      binayriStrng += stack.pop()
  }
  return binayriStrng
}

    //【】_ 